package com.yanghs.shiro.filter;

import com.yanghs.common.dao.RedisDao;
import com.yanghs.common.entity.hbm.Userinfo;
import com.yanghs.common.util.SerializeUtil;
import com.yanghs.shiro.session.IRedisRepository;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.mgt.DefaultSessionKey;
import org.apache.shiro.session.mgt.SessionManager;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.AccessControlFilter;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;
import java.io.Serializable;
import java.util.Deque;
import java.util.LinkedList;

/**
 * @author yanghs
 * @Description:用户并发控制
 * @date 2018/3/22 16:40
 */
public class KickoutSessionFilter extends AccessControlFilter {
    private SessionManager sessionManager;
    private IRedisRepository redisRepository;
    private int maxSession;
    private boolean after;

    /**
     * isAccessAllowed是否允许访问 true允许 false拒绝访问
     * @param servletRequest
     * @param servletResponse
     * @param o
     * @return
     * @throws Exception
     */
    protected boolean isAccessAllowed(ServletRequest servletRequest, ServletResponse servletResponse, Object o) throws Exception {
        Subject subject = getSubject(servletRequest,servletResponse);
        if(!subject.isAuthenticated()){
            return true;
        }
        Session session = subject.getSession();

        if(session.getAttribute("kickout")!=null){
            return false;
        }
        Serializable sessionId = session.getId();
        String account = (String) session.getAttribute("account");

        /*队列的方式 可以两边删除 得到用户-sessionid信息便于控制 一用户多地方登陆*/
        Deque<Serializable> deque = redisRepository.getAccountSessions(account);

        if(deque == null){
            deque = new LinkedList<Serializable>();
            deque.add(sessionId);
            redisRepository.saveAccountSessions(account,deque);
        }

        if(!deque.contains(sessionId)){
            deque.add(sessionId);
            redisRepository.saveAccountSessions(account,deque);
        }
        if(deque.size()>maxSession){
            /*强制退出sessionid*/
            Serializable kickoutId = null;
            if(after){
                kickoutId =  deque.removeLast();
            }else{
                kickoutId =  deque.removeFirst();
            }
            Session kickoutSession = sessionManager.getSession(new DefaultSessionKey(kickoutId));
            if(kickoutSession != null){
                kickoutSession.setAttribute("kickout",true);
            }
            redisRepository.saveAccountSessions(account,deque);
        }
        if(session.getAttribute("kickout")!= null){
            return false;
        }

        return true;
    }

    /**
     * 拒绝访后是否自己处理 true 自己不不处理并且继续执行拦截执行链 false表示自己已经处理了将直接返回
     * @param servletRequest
     * @param servletResponse
     * @return
     * @throws Exception
     */
    protected boolean onAccessDenied(ServletRequest servletRequest, ServletResponse servletResponse) throws Exception {
        Subject subject = getSubject(servletRequest,servletResponse);
        subject.logout();
        ((HttpServletResponse)servletResponse).sendRedirect("login.do");
        return false;
    }


    public SessionManager getSessionManager() {
        return sessionManager;
    }

    public void setSessionManager(SessionManager sessionManager) {
        this.sessionManager = sessionManager;
    }

    public int getMaxSession() {
        return maxSession;
    }

    public void setMaxSession(int maxSession) {
        this.maxSession = maxSession;
    }

    public boolean isAfter() {
        return after;
    }

    public void setAfter(boolean after) {
        this.after = after;
    }
    public IRedisRepository getRedisRepository() {
        return redisRepository;
    }

    public void setRedisRepository(IRedisRepository redisRepository) {
        this.redisRepository = redisRepository;
    }

}
